﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace DcsGauges.Testing.Utils
{
    public class ThrowAssert
    {
        #region No specific exception type

        public static void ThrowsAny<TResult>(Func<TResult> blockToExecute)
        {
            try
            {
                blockToExecute();
                NoExceptionWasThrown();
            }
            catch (Exception exc)
            {
                Assert.IsTrue(true, "Exception catched: Message = " + exc.Message);
            }
        }


        public static void ThrowsAny<TResult, TArg0>(Func<TArg0, TResult> blockToExecute, TArg0 arg0)
        {
            try
            {
                blockToExecute(arg0);
                NoExceptionWasThrown();
            }
            catch
            {
                Assert.IsTrue(true, "Exception catched");
            }
        }


        public static void ThrowsAny<TResult, TArg0, TArg1>(Func<TArg0, TArg1, TResult> blockToExecute, TArg0 arg0, TArg1 arg1)
        {
            try
            {
                blockToExecute(arg0, arg1);
                NoExceptionWasThrown();
            }
            catch
            {
                Assert.IsTrue(true, "Exception catched");
            }
        }


        #endregion


        #region With Exception Type

        #region IncludingReturnType
        public static void Throws<TException, TResult>(Func<TResult> blockToExecute) where TException : Exception
        {
            try
            {
                blockToExecute();
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TException, T, TResult>(Func<T, TResult> blockToExecute, T argument) where TException : Exception
        {
            try
            {
                blockToExecute(argument);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TExcepiton, T1, T2, TResult>(Func<T1, T2, TResult> blockToExecute, T1 argument1, T2 argument2) where TExcepiton : Exception
        {
            try
            {
                blockToExecute(argument1, argument2);
                NoExceptionWasThrown<TExcepiton>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TExcepiton>(exc);
            }
        }



        public static void Throws<TException, T1, T2, T3, TResult>(Func<T1, T2, T3, TResult> blockToExecute, T1 argument1, T2 argument2, T3 argument3) where TException : Exception
        {
            try
            {
                blockToExecute(argument1, argument2, argument3);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TExcetption, T1, T2, T3, T4, TResult>(Func<T1, T2, T3, T4, TResult> blockToExecute, T1 argument1, T2 argument2, T3 argument3, T4 argument4) where TExcetption : Exception
        {
            try
            {
                blockToExecute(argument1, argument2, argument3, argument4);
                NoExceptionWasThrown<TExcetption>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TExcetption>(exc);
            }
        }


        public static void Throws<TExcetption, T1, T2, T3, T4, T5, TResult>(Func<T1, T2, T3, T4, T5, TResult> blockToExecute, T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5) where TExcetption : Exception
        {
            try
            {
                blockToExecute(argument1, argument2, argument3, argument4, argument5);
                NoExceptionWasThrown<TExcetption>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TExcetption>(exc);
            }
        }


        public static void Throws<TExcetption, T1, T2, T3, T4, T5, T6, TResult>(Func<T1, T2, T3, T4, T5, T6, TResult> blockToExecute, T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5, T6 argument6) where TExcetption : Exception
        {
            try
            {
                blockToExecute(argument1, argument2, argument3, argument4, argument5, argument6);
                NoExceptionWasThrown<TExcetption>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TExcetption>(exc);
            }
        }


        public static void Throws<TExcetption, T1, T2, T3, T4, T5, T6, T7, TResult>(Func<T1, T2, T3, T4, T5, T6, T7, TResult> blockToExecute, T1 argument1, T2 argument2, T3 argument3, T4 argument4, T5 argument5, T6 argument6, T7 argument7) where TExcetption : Exception
        {
            try
            {
                blockToExecute(argument1, argument2, argument3, argument4, argument5, argument6, argument7);
                NoExceptionWasThrown<TExcetption>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TExcetption>(exc);
            }
        }

        #endregion

        #region NoReturnType

        public static void Throws<TException>(Action blockToExecute) where TException : Exception
        {
            try
            {
                blockToExecute();
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }

        public static void Throws<TException, T1>(Action<T1> blockToExecute, T1 arg1) where TException : Exception
        {
            try
            {
                blockToExecute(arg1);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TException, T1, T2>(Action<T1, T2> blockToExecute, T1 arg1, T2 arg2) where TException : Exception
        {
            try
            {
                blockToExecute(arg1, arg2);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TException, T1, T2, T3>(Action<T1, T2, T3> blockToExecute, T1 arg1, T2 arg2, T3 arg3) where TException : Exception
        {
            try
            {
                blockToExecute(arg1, arg2, arg3);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }


        public static void Throws<TException, T1, T2, T3, T4>(Action<T1, T2, T3, T4> blockToExecute, T1 arg1, T2 arg2, T3 arg3, T4 arg4) where TException : Exception
        {
            try
            {
                blockToExecute(arg1, arg2, arg3, arg4);
                NoExceptionWasThrown<TException>();
            }
            catch (Exception exc)
            {
                ErrorMessage<TException>(exc);
            }
        }

        #endregion

        public static void ErrorMessage<TException>(Exception exc) where TException : Exception
        {
            if (exc.GetType() == typeof(AssertFailedException))
                throw exc;

            Assert.IsTrue(exc.GetType() == typeof(TException), "Expected exception of type " + typeof(TException) + " but type of " + exc.GetType() + " was thrown instead.");
        }

        private static void NoExceptionWasThrown<TException>() where TException : Exception
        {
            Assert.Fail("An Exception of type [" + typeof(TException).Name + "] was expected but none was thrown");
        }

        private static void NoExceptionWasThrown()
        {
            Assert.Fail("An Exception was exptected but none was thrown");
        }

        #endregion
    }
}
